using System;
using System.Collections;
using System.Collections.Generic;

namespace SharpMud.LPC
{
    public class Mapping : LPC.Object, IDictionary<string, Object>, IDictionary<String, Object>, IList<MappingEntry>
	{
		#region Private Members

		private object													_syncRoot;
        private List<MappingEntry>        _Contents;

		#endregion

        #region Constructors
        public Mapping()
        {
            _Contents = new List<MappingEntry>();
        }
        public Mapping(params MappingEntry[] contents)
        {
            _Contents = new List<MappingEntry>(contents);
        }
        public Mapping(IList<MappingEntry> contents)
        {
            _Contents = new List<MappingEntry>(contents);
        }
        #endregion

        #region Static Stuff
        public static explicit operator MappingEntry[](Mapping val)
        {
            return val._Contents.ToArray();
        }
        public static explicit operator Mapping(MappingEntry[] val)
        {
            return new Mapping(val);
        }

        public static explicit operator Array(Mapping val)
        {
            return new Array((Object[])(val._Contents.ToArray()));
        }
		#endregion

		public override string ToParsableString()
		{
            return ((Array)this).ToParsableString();
		}

        protected override Object Clone()
        {
            Mapping lm = new Mapping();
            for (int x = 0; x < this._Contents.Count; x++)
            {
                lm.Add((String)_Contents[x].Key.Clone(), (Object)((ICloneable)_Contents[x].Value).Clone());
            }
            return lm;
        }

        #region IDictionary<string,Object> Members

        void IDictionary<string, Object>.Add(string key, Object value)
        {
            if (GetKeyIndex(key) != -1)
                throw new System.Exception("Key already exists in Mapping.");
            _Contents.Add(new MappingEntry(key, value));
        }

        bool IDictionary<string, Object>.ContainsKey(string key)
        {
            if (GetKeyIndex(key) == -1)
                return false;
            else
                return true;
        }

        ICollection<string> IDictionary<string, Object>.Keys
        {
            get
            {
                List<string> l = new List<string>();
                foreach (MappingEntry lme in this._Contents)
                {
                    l.Add(lme.Key);
                }
                return (ICollection<string>)l;
            }
        }

        bool IDictionary<string, Object>.Remove(string key)
        {
            int i = GetKeyIndex(key);
            if (i == -1)
                return false;
            _Contents.RemoveAt(i);
            return true;
        }

        bool IDictionary<string, Object>.TryGetValue(string key, out Object value)
        {
            int i = GetKeyIndex(key);
            if (i == -1)
            {
                value = null;
                return false;
            }
            else
            {
                value = _Contents[i].Value;
                return true;
            }
        }

        ICollection<Object> IDictionary<string, Object>.Values
        {
            get
            {
                List<Object> l = new List<Object>();
                foreach (MappingEntry lme in this._Contents)
                {
                    l.Add(lme.Value);
                }
                return (ICollection<Object>)l;
            }
        }

        public Object this[string key]
        {
            get
            {
                if (key == null)
                    throw new ArgumentNullException("key");

                int i = GetKeyIndex(key);
                if (i == -1)
                    return null;
                else
                    return _Contents[i].Value;
            }
            set
            {
                if (key == null)
                    throw new ArgumentNullException("key");

                int i = GetKeyIndex(key);
                if (i == -1)
                {
                    this.Add((String)key, value);
                }
                else
                {
                    _Contents[i].Value = value;
                }
            }
        }

        #endregion

        #region ICollection<KeyValuePair<string,Object>> Members

        void ICollection<KeyValuePair<string, Object>>.Add(KeyValuePair<string, Object> item)
        {
            _Contents.Add(new MappingEntry(item.Key, item.Value));
        }

        void ICollection<KeyValuePair<string, Object>>.Clear()
        {
            _Contents.Clear();
        }

        bool ICollection<KeyValuePair<string, Object>>.Contains(KeyValuePair<string, Object> item)
        {
            if (this[item.Key] == item.Value)
                return true;
            else
                return false;
        }

        void ICollection<KeyValuePair<string, Object>>.CopyTo(KeyValuePair<string, Object>[] array, int arrayIndex)
        {
            if ((arrayIndex + this._Contents.Count) >= array.Length)
                throw new IndexOutOfRangeException();
            for (int x = 0; x < this._Contents.Count; x++)
            {
                array.SetValue(new KeyValuePair<string, Object>(_Contents[x].Key, _Contents[x].Value), x + arrayIndex);
            }
        }

        int ICollection<KeyValuePair<string, Object>>.Count
        {
            get { return _Contents.Count; }
        }

        bool ICollection<KeyValuePair<string, Object>>.IsReadOnly
        {
            get { return false; }
        }

        bool ICollection<KeyValuePair<string, Object>>.Remove(KeyValuePair<string, Object> item)
        {
            int i = GetKeyIndex(item.Key);
            if (i == -1)
                return false;
            if (_Contents[i].Value != item.Value)
                return false;
            _Contents.RemoveAt(i);
            return true;
        }

        #endregion

        #region IEnumerable<KeyValuePair<string,Object>> Members

        IEnumerator<KeyValuePair<string, Object>> IEnumerable<KeyValuePair<string, Object>>.GetEnumerator()
        {
            return (IEnumerator<KeyValuePair<string,Object>>)(new Mapping.MappingEnumerator(this));
        }

        #endregion

        #region IList<MappingEntry> Members

        int IList<MappingEntry>.IndexOf(MappingEntry item)
        {
            return _Contents.IndexOf(item);
        }

        void IList<MappingEntry>.Insert(int index, MappingEntry item)
        {
            _Contents.Insert(index, item);
        }

        void IList<MappingEntry>.RemoveAt(int index)
        {
            _Contents.RemoveAt(index);
        }

        MappingEntry IList<MappingEntry>.this[int index]
        {
            get
            {
                return _Contents[index];
            }
            set
            {
                _Contents[index] = value;
            }
        }

        #endregion

        #region ICollection<MappingEntry> Members

        void ICollection<MappingEntry>.Add(MappingEntry item)
        {
            _Contents.Add(item);
        }

        void ICollection<MappingEntry>.Clear()
        {
            _Contents.Clear();
        }

        bool ICollection<MappingEntry>.Contains(MappingEntry item)
        {
            return _Contents.Contains(item);
        }

        void ICollection<MappingEntry>.CopyTo(MappingEntry[] array, int arrayIndex)
        {
            if ((arrayIndex + this._Contents.Count) >= array.Length)
                throw new IndexOutOfRangeException();
            for (int x = 0; x < this._Contents.Count; x++)
            {
                array.SetValue(new MappingEntry(),x+arrayIndex);
            }
        }

        int ICollection<MappingEntry>.Count
        {
            get { return _Contents.Count; }
        }

        bool ICollection<MappingEntry>.IsReadOnly
        {
            get { return false; }
        }

        bool ICollection<MappingEntry>.Remove(MappingEntry item)
        {
            if (!_Contents.Contains(item))
                return false;
            _Contents.Remove(item);
            return true;
        }

        #endregion

        #region IEnumerable<MappingEntry> Members

        IEnumerator<MappingEntry> IEnumerable<MappingEntry>.GetEnumerator()
        {
            return new Mapping.MappingEnumerator(this);
        }

        #endregion

        #region IEnumerable Members

        IEnumerator IEnumerable.GetEnumerator()
        {
            return new Mapping.MappingEnumerator(this);
        }

        #endregion

        #region IDictionary<String,Object> Members

        public void Add(String key, Object value)
        {
            if (key.Value is int)
                throw new ArgumentNullException("key");
            if(value==null)
                throw new ArgumentNullException("value");
            if (this.ContainsKey(key))
                throw new System.Exception("Key already exists in the Mapping.");
            this._Contents.Add(new MappingEntry((string)key.Value, value));
        }

        public bool ContainsKey(String key)
        {
            if (key == null)
                throw new ArgumentNullException("key");
            if (key.Value is int)
                throw new ArgumentNullException("key");

            return (GetKeyIndex(key) != (-1));
        }

        public ICollection<String> Keys
        {
            get
            {
                List<String> l = new List<String>();
                foreach (MappingEntry lme in this._Contents)
                {
                    l.Add((String)lme.Key);
                }
                return (ICollection<String>)l;
            }
        }

        public bool Remove(String key)
        {
            if (key == null)
                throw new ArgumentNullException("key");
            if (key.Value is int)
                throw new ArgumentNullException("key");

            int i = GetKeyIndex(key);
            if (i == -1)
                return false;
            _Contents.RemoveAt(i);
            return true;
        }

        public int GetKeyIndex(string key)
        {
            if (key == null)
                throw new ArgumentNullException("key");

            return GetKeyIndex((String)key);
        }

        public int GetKeyIndex(String key)
        {
            if (key == null)
                throw new ArgumentNullException("key");
            if (key.Value is int)
                throw new ArgumentNullException("key");

            string kv = ((string)key.Value).Trim().ToLower();
            for (int x = 0; x < _Contents.Count; x++)
            {
                if (_Contents[x].Key.Trim().ToLower() == kv)
                    return x;
            }
            return -1;
        }

        public bool TryGetValue(String key, out Object value)
        {
            int i = GetKeyIndex(key);
            if (i == -1)
            {
                value = null;
                return false;
            }
            else
            {
                value = _Contents[i].Value;
                return true;
            }
        }

        public ICollection<Object> Values
        {
            get
            {
                List<Object> l = new List<Object>();
                foreach (MappingEntry lme in this._Contents)
                {
                    l.Add(lme.Value);
                }
                return (ICollection<Object>)l;
            }
        }

        public Object this[String key]
        {
            get
            {
                if (key == null)
                    throw new ArgumentNullException("key");
                if (key.Value is int)
                    throw new ArgumentNullException("key");

                int i = GetKeyIndex(key);
                if (i == -1)
                    return null;
                else
                    return _Contents[i].Value;
            }
            set
            {
                if (key == null)
                    throw new ArgumentNullException("key");
                if (key.Value is int)
                    throw new ArgumentNullException("key");

                int i = GetKeyIndex(key);
                if (i == -1)
                {
                    this.Add(key, value);
                }
                else
                {
                    _Contents[i].Value = value;
                }
            }
        }

        #endregion

        #region ICollection<KeyValuePair<String,Object>> Members

        public void Add(KeyValuePair<String, Object> item)
        {
            Add(item.Key, item.Value);
        }

        public void Clear()
        {
            _Contents.Clear();
        }

        public bool Contains(KeyValuePair<String, Object> item)
        {
            if (this[item.Key] == item.Value)
                return true;
            else
                return false;
        }

        public void CopyTo(KeyValuePair<String, Object>[] array, int arrayIndex)
        {
            if ((arrayIndex + this._Contents.Count) >= array.Length)
                throw new IndexOutOfRangeException();
            for (int x = 0; x < this._Contents.Count; x++)
            {
                array.SetValue(new KeyValuePair<String, Object>((String)_Contents[x].Key, _Contents[x].Value),x+arrayIndex);
            }
        }

        public int Count
        {
            get
            {
                return this._Contents.Count;
            }
        }

        public bool IsReadOnly
        {
            get
            {
                return false;
            }
        }

        public bool Remove(KeyValuePair<String, Object> item)
        {
            int i = GetKeyIndex(item.Key);
            if (i == -1)
                return false;
            if (_Contents[i].Value != item.Value)
                throw new Exception("Item value mismatch.");
            _Contents.RemoveAt(i);
            return true;
        }

        #endregion

        #region IEnumerable<KeyValuePair<String,Object>> Members

        public IEnumerator<KeyValuePair<String, Object>> GetEnumerator()
        {
            return (IEnumerator<KeyValuePair<String, Object>>)(new Mapping.MappingEnumerator(this));
        }

        #endregion

        private class MappingEnumerator : IEnumerator<MappingEntry>, IDictionaryEnumerator, IEnumerator<KeyValuePair<string, Object>>, IEnumerator<KeyValuePair<String, Object>> //System.Collections.IEnumerator, System.Collections.IDictionaryEnumerator
        {
            private int index;
            private Mapping la;

            internal MappingEnumerator(Mapping val)
            {
                la = val;
                index = -1;
            }

            public MappingEntry Entry
            {
                get
                {
                    if (index < 0)
                        throw new InvalidOperationException();
                    if (index >= la._Contents.Count)
                        throw new InvalidOperationException();
                    return la._Contents[index];
                }
            }

            #region Old Code

            //#region IEnumerator Members

            //public void Reset()
            //{
            //    index = -1;
            //}

            //public object Current
            //{
            //    get
            //    {
            //        if(index<0 || index>=la.Count)
            //            throw new InvalidOperationException("The enumerator is positioned before the first element of the collection or after the last element.");

            //        return la._Contents. .GetValue(index);
            //    }
            //}

            //    public bool MoveNext()
            //    {
            //        index++;
            //        if (index >= la.Count)
            //            return false;
            //        else
            //            return true;
            //    }

            //#endregion

            //    #region IDictionaryEnumerator Members

            //    object IDictionaryEnumerator.Key
            //    {
            //        get
            //        {
            //            return la._Contents.GetKey(index);
            //        }
            //    }

            //    public string Key
            //    {
            //        get
            //        {
            //            return la._Contents.GetKey(index);
            //        }
            //    }

            //    object IDictionaryEnumerator.Value
            //    {
            //        get
            //        {
            //            return (object)la._Contents.GetValue(index);
            //        }
            //    }

            //    public Object Value
            //    {
            //        get
            //        {
            //            return (Object)(la._Contents.GetValue(index));
            //        }
            //    }

            //    public System.Collections.DictionaryEntry Entry
            //    {
            //        get
            //        {
            //            return la._Contents.GetEntry(index);
            //        }
            //    }

            //    #endregion
            #endregion

            #region IDictionaryEnumerator Members

            DictionaryEntry IDictionaryEnumerator.Entry
            {
                get { return new DictionaryEntry(Entry.Key, Entry.Value); }
            }

            object IDictionaryEnumerator.Key
            {
                get { return Entry.Key; }
            }

            object IDictionaryEnumerator.Value
            {
                get { return Entry.Value; }
            }

            #endregion

            #region IEnumerator Members

            object IEnumerator.Current
            {
                get { return Entry; }
            }

            bool IEnumerator.MoveNext()
            {
                index++;
                if (index >= la._Contents.Count)
                    return true;
                else
                    return false;
            }

            void IEnumerator.Reset()
            {
                index = -1;
            }

            #endregion

            #region IEnumerator<MappingEntry> Members

            MappingEntry IEnumerator<MappingEntry>.Current
            {
                get { return Entry; }
            }

            #endregion

            #region IDisposable Members

            void IDisposable.Dispose()
            {
                la = null;
            }

            #endregion

            #region IEnumerator<KeyValuePair<string,Object>> Members

            KeyValuePair<string, Object> IEnumerator<KeyValuePair<string, Object>>.Current
            {
                get { return new KeyValuePair<string,Object>(Entry.Key,Entry.Value); }
            }

            #endregion

            #region IEnumerator<KeyValuePair<String,Object>> Members

            KeyValuePair<String, Object> IEnumerator<KeyValuePair<String, Object>>.Current
            {
                get { return new KeyValuePair<String, Object>((String)Entry.Key, Entry.Value); }
            }

            #endregion
        }
    }
}
